import { useEffect, useRef, useState } from 'react'
import styles from './scss/MusicImport.module.scss'
import { type Midi } from '@tonejs/midi'
import ToneMidi, {
  loadSongFromMidi,
  NonExistentNote,
} from '@/lib/music/ToneMidi'
import { showToast } from '@/utils/toast'
import CheckBox from '@/components/ChechBox'
import { getMusicKeyByNote } from '@/lib/music/data'
import { musicListStore } from '@/store/musicListStore'
import { showLoading } from '@/utils/loading'
import { music_exists_notes } from '@/lib/music/musicNote'
import problemSvg from '@/assets/svg/problem.svg'
import { MessageBox } from '@/utils/messageBox'
import ProgressBar from '@/components/ProgressBar'

function onNonExistentNoteHelpHandler() {
  MessageBox.info(
    '不存在的音符',
    '本钢琴超出范围的音符（钢琴键不存在），可以用其他音符替换或者直接忽略'
  )
}
const help = (content: string) => {
  MessageBox.info('帮助', content)
}

export default function MusicImport() {
  // const [file, setFile] = useState<File | null>(null)
  const [midiData, setMidiData] = useState<Midi | null>(null)
  const fileInput = useRef<HTMLInputElement>(null)
  const [checkChacksState, setCheckChacksState] = useState<boolean[]>([])
  const [importName, setImportName] = useState<string>('')
  const [nonExistentNotes, setNonExistentNotes] = useState<NonExistentNote[]>(
    []
  )
  const [timeScaling, setTimeScaling] = useState<number>(1)
  const [droping, setDroping] = useState<boolean>(false)
  const [keyboardExclude, setKeyboardExclude] = useState<boolean>(false)

  function onFileChange(file: File | null) {
    if (!file) return
    if (!(file.name.endsWith('.mid') || file.name.endsWith('.midi'))) {
      showToast('文件格式错误,请选择.mid或.midi文件')
      return
    }
    const closeLoading = showLoading('加载文件中')
    const reader = new FileReader()
    reader.onload = (e) => {
      closeLoading()
      if (!e.target?.result) {
        showToast('文件读取失败')
        return
      }
      if (!(e.target.result instanceof ArrayBuffer)) {
        showToast('文件格式错误')
        return
      }
      try {
        const midi = new ToneMidi(e.target.result)
        //  file.name.split('.')[0]
        if (!midi.name) {
          midi.name = file.name.split('.')[0]
        }
        setMidiData(midi)
      } catch (e) {
        showToast('文件解析失败')
      }
    }
    reader.onerror = (e) => {
      console.error(e)
      closeLoading()
      showToast('文件读取失败')
    }
    reader.readAsArrayBuffer(file)
  }
  function importHandler() {
    if (!midiData) return
    const checkedTracks = midiData.tracks.filter(
      (_, index) => checkChacksState[index]
    )
    if (checkedTracks.length === 0) {
      MessageBox.warn('MIDI导入', '请选择要导入的轨道')
      return
    }
    if (!importName.trim()) {
      MessageBox.warn('MIDI导入', '请输入导入名称')
      return
    }
    if (
      musicListStore.value.list.find((item) => item.name === importName.trim())
    ) {
      MessageBox.warn('MIDI导入', '导入名称已存在')
      return
    }
    const song = loadSongFromMidi(
      importName.trim(),
      checkedTracks,
      midiData,
      nonExistentNotes,
      keyboardExclude,
      1 / timeScaling
    )
    musicListStore.setValue('list', [song, ...musicListStore.value.list])
    MessageBox.info('MIDI导入', '导入成功')
    setMidiData(null)
  }
  useEffect(() => {
    if (midiData) {
      setCheckChacksState(midiData.tracks.map(() => false))
      setImportName(midiData.name)
    }
  }, [midiData])
  useEffect(() => {
    if (!midiData) {
      setNonExistentNotes([])
      return
    }
    const list: NonExistentNote[] = []
    const pushList = (note: string) => {
      const index = list.findIndex((item) => item.note === note)
      if (index != -1) {
        list[index].count++
        return
      }
      list.push({ note, count: 1, replaceNote: null })
    }
    checkChacksState.forEach((item, index) => {
      if (!item) return
      const track = midiData.tracks[index]
      if (!track) return
      track.notes.forEach((note) => {
        const key = getMusicKeyByNote(note.name)
        if (key == null) {
          pushList(note.name)
        }
      })
    })
    setNonExistentNotes(list)
  }, [checkChacksState, midiData])
  if (midiData && checkChacksState.length < midiData.tracks.length) {
    for (let i = 0; i < midiData.tracks.length - checkChacksState.length; i++) {
      checkChacksState.push(false)
    }
  }
  const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
    e.stopPropagation()
    setDroping(false)
    switch (e.dataTransfer.types[0]) {
      case 'Files':
        const file = e.dataTransfer.files[0]
        onFileChange(file)
        break
      default:
        showToast('文件格式错误,请选择.mid或.midi文件')
        break
    }
  }
  const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
    e.stopPropagation()
    e.dataTransfer.dropEffect = 'copy'
    if (!droping) {
      setDroping(true)
    }
  }
  return (
    <div
      className={styles['music-import-view']}
      onDragOver={handleDragOver}
      onDrop={handleDrop}
      onDragExit={() => setDroping(false)}
      onDragLeave={() => setDroping(false)}>
      {droping && (
        <div className={styles['file-drop-mask']}>
          <div className={styles['file-drop-mask-text']}>松开鼠标导入</div>
        </div>
      )}

      <button
        className={styles['music-import-btn']}
        onClick={() => {
          fileInput.current?.click()
        }}>
        {midiData ? '重新选择文件' : '选择文件'}
      </button>
      <div style={{ height: '20px' }}></div>
      <input
        type="file"
        accept=".mid,.midi"
        ref={fileInput}
        // @ts-ignore
        onChange={(e) => onFileChange(e.target.files[0] || null)}
        style={{ display: 'none' }}
      />
      {midiData && (
        <>
          <div className={styles['field-group']}>
            <div className={styles['title']}>名称:</div>
            <input
              type="text"
              value={importName}
              onChange={(e) => setImportName(e.target.value)}
            />
          </div>
          <div className={styles['field-group']}>
            <div className={styles['title']}>总时长:</div>
            <div className={styles['value']}>
              {midiData.duration.toFixed(1)}秒
            </div>
          </div>
          <div className={styles['title']}>轨道:</div>
          <div className={styles['track-list']}>
            <div className={styles['track-item']}>
              <div className={styles['header']}>轨道名称</div>
              <div className={styles['header']}>音节数量</div>
              <div className={styles['header']}>是否导入</div>
            </div>
            {midiData.tracks.map((track, index) => {
              return (
                <div className={styles['track-item']} key={index}>
                  <div
                    className={styles['name']}
                    style={{
                      color: track.name?.trim() ? 'unset' : '#BBB',
                    }}>
                    {track.name || '未命名轨道'}
                  </div>
                  <div className={styles['count']}>{track.notes.length}</div>
                  <CheckBox
                    className={styles['checkbox']}
                    checked={checkChacksState[index]}
                    onChange={(cheched) => {
                      setCheckChacksState((prev) => {
                        const newCheckChacksState = [...prev]
                        newCheckChacksState[index] = cheched
                        return [...newCheckChacksState]
                      })
                    }}
                  />
                </div>
              )
            })}
          </div>
          {nonExistentNotes.length > 0 && (
            <>
              <div className={styles['title']}>
                不存在的音符:
                <img
                  src={problemSvg.src}
                  className={styles['help']}
                  onClick={() => onNonExistentNoteHelpHandler()}></img>
              </div>
              <div className={styles['track-list']}>
                <div className={styles['track-item']}>
                  <div className={styles['header']}>音符</div>
                  <div className={styles['header']}>数量</div>
                  <div className={styles['header']}>替换音符</div>
                </div>
                {nonExistentNotes.map((item, index) => {
                  return (
                    <div className={styles['track-item']} key={item.note}>
                      <div className={styles['name']}>{item.note}</div>
                      <div className={styles['count']}>{item.count}</div>
                      <div className={styles['pingti']}>
                        <select
                          value={item.replaceNote || ''}
                          onChange={(e) => {
                            setNonExistentNotes((prev) => {
                              const newNonExistentNotes = [...prev]
                              newNonExistentNotes[index].replaceNote =
                                e.target.value || null
                              return [...newNonExistentNotes]
                            })
                          }}>
                          <option value="">忽略</option>
                          {music_exists_notes.map((note) => {
                            return (
                              <option value={note} key={note}>
                                {note}
                              </option>
                            )
                          })}
                        </select>
                        {/* {item.replaceNote} */}
                      </div>
                    </div>
                  )
                })}
              </div>
            </>
          )}
          <div className={styles['field-group']}>
            <div className={styles['title']}>
              排除键盘不可能音符
              <img
                src={problemSvg.src}
                className={styles['help']}
                onClick={() =>
                  help(
                    '清除键盘上不可能同时按下的音符，例如键盘提示按下黑键或白键，（按黑键需要shift）实际无法同时按下\n如果黑白键同时出现，会优先保留白键'
                  )
                }></img>
              :
            </div>
            <div className={styles['value']}>
              <CheckBox
                checked={keyboardExclude}
                onChange={(v) => setKeyboardExclude(v)}
              />
            </div>
          </div>
          <div className={styles['field-group']}>
            <div className={styles['title']}>时间缩放 :</div>
            <div className={styles['value']} style={{ width: 200 }}>
              <ProgressBar
                min={0.25}
                max={4}
                progress={(timeScaling - 0.25) / 3.75}
                onChange={(v) => setTimeScaling(+v.toFixed(2))}
              />
            </div>
            <div className={styles['value']}>
              <span>x{timeScaling}</span>
            </div>
          </div>

          <button
            className={styles['music-import-btn']}
            onClick={() => importHandler()}>
            导入
          </button>
        </>
      )}
    </div>
  )
}
